package com.cl.code.database.mybatis.module.sql.method;

import com.cl.code.database.mybatis.constant.CLMybatisConstants;
import com.cl.code.database.mybatis.module.sql.table.TableInfo;
import com.cl.code.database.mybatis.util.SqlScriptUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.builder.SqlSourceBuilder;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Method;

/**
 * @author chengliang
 * @since 1.0.0
 */
public abstract class AbstractSqlMethod implements SqlMethod {

    protected final Class<?> type;
    protected final Configuration configuration;
    protected final LanguageDriver languageDriver;
    protected final Method method;
    protected Class<?> parameterType = null;
    protected final TableInfo tableInfo;


    public AbstractSqlMethod(Class<?> type, Method method, TableInfo tableInfo, Configuration configuration) {
        this.type = type;
        this.method = method;
        this.configuration = configuration;
        this.tableInfo = tableInfo;
        this.languageDriver = configuration.getDefaultScriptingLanguageInstance();
    }

    @Override
    public SqlSource getSqlSource() {
        return this.languageDriver.createSqlSource(this.configuration, SqlSourceBuilder.removeExtraWhitespaces(buildSql()), getParameterType());
    }

    protected abstract String buildSql();

    @Override
    public Class<?> getParameterType() {
        if (this.parameterType != null) {
            return this.parameterType;
        }
        Class<?>[] parameterTypes = method.getParameterTypes();
        for (Class<?> currentParameterType : parameterTypes) {
            if (!RowBounds.class.isAssignableFrom(currentParameterType)
                    && !ResultHandler.class.isAssignableFrom(currentParameterType)) {
                if (this.parameterType == null) {
                    this.parameterType = currentParameterType;
                } else {
                    this.parameterType = MapperMethod.ParamMap.class;
                }
            }
        }
        return this.parameterType;
    }

    protected String getWhereSql() {

        String whereSqlParam = CLMybatisConstants.WHERE_PARAM_NAME + "." + CLMybatisConstants.WHERE_SQL;

        String whereSqlPlaceholder = "${" + whereSqlParam + "}";

        String where = SqlScriptUtils.convertWhere(SqlScriptUtils.convertIf(String.format("%s != null and %s != ''", whereSqlParam, whereSqlParam), whereSqlPlaceholder, true));

        return SqlScriptUtils.convertIf(String.format("%s != null", CLMybatisConstants.WHERE_PARAM_NAME), where, true);

    }

}
